package edu.xhu.homepage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.json.JSONUtil;
import edu.xhu.homepage.mapper.BiliMainChannelMapper;
import edu.xhu.homepage.service.BiliChannelService;

import edu.xhu.model.common.constants.MainChannelConstants;
import edu.xhu.model.common.dtos.ResponseResult;
import edu.xhu.model.common.enums.AppHttpCodeEnum;
import edu.xhu.model.video.pojos.BiliMainChannel;
import edu.xhu.model.video.vos.BiliMainChannelVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.*;

@Service
@RequiredArgsConstructor
@Slf4j
public class BiliBiliChannelServiceImpl implements BiliChannelService {


    private final StringRedisTemplate redisTemplate;

    private final BiliMainChannelMapper biliMainChannelMapper;
    //双检加锁之锁对象
    private final Object mainChannelQueryLock = new Object();
    @Override
    public ResponseResult<?> queryMainChannels() {
        List<BiliMainChannelVo> biliMainChannelVoList = null;
        //定义一个String类型的变量，用于存放视频主分区的json
        String biliMainChannelJson = null;


        //从redis中获取视频主分区的json
        //先查询A缓存
        biliMainChannelJson = (String) this.redisTemplate.opsForValue().get(MainChannelConstants.MAINCHANNEL_REDIS_KEY_A);
        //如果redis中没有视频主分区的json，则从redis中获取视频主分区的json
        //再查询B缓存
        if (biliMainChannelJson == null) {
            biliMainChannelJson = (String) this.redisTemplate.opsForValue().get(MainChannelConstants.MAINCHANNEL_REDIS_KEY_B);
            //如果redis中没有视频主分区的json，则从mysql中获取视频主分区的json
            if (biliMainChannelJson == null) {
                //加锁
                synchronized (mainChannelQueryLock) {
                    //从redis中获取视频主分区的json
                    biliMainChannelJson = (String) this.redisTemplate.opsForValue().get(MainChannelConstants.MAINCHANNEL_REDIS_KEY_A);
                    //再查A缓存
                    //如果redis中没有视频主分区的json，则从mysql中获取视频主分区的json
                    if (biliMainChannelJson == null)
                        biliMainChannelJson = (String) this.redisTemplate.opsForValue().get(MainChannelConstants.MAINCHANNEL_REDIS_KEY_B);
                    //如果redis中没有视频主分区的json，则从mysql中获取视频主分区的json
                    //再查B缓存
                    if (biliMainChannelJson == null) {
                        //从mysql中获取视频主分区的json
                        biliMainChannelJson
                                = getMainChannelJson();
                        //将视频主分区的json存储到redis中
                        this.redisTemplate.opsForValue().set(MainChannelConstants.MAINCHANNEL_REDIS_KEY_A, biliMainChannelJson);
                        this.redisTemplate.opsForValue().set(MainChannelConstants.MAINCHANNEL_REDIS_KEY_B, biliMainChannelJson);
                    }
                }
            }
        }
        //如果redis中没有主分区的json，则返回错误结果
        if (biliMainChannelJson == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "主分区redis，mysql都失败了");
        }
        //将主分区的json转换为MainChannelVo类型的list
        biliMainChannelVoList = JSONUtil.toBean(biliMainChannelJson, new TypeReference<List<BiliMainChannelVo>>() {
        }, true);
        //返回主分区的list
        return ResponseResult.okResult(biliMainChannelVoList);
    }

    private String getMainChannelJson() {
        //存储主分区所有信息
        //<mainchannelid,MainChannelVo>
        // 存储视频ID (mainchannelid) 与 MainChannelVo 对象的对应关系
        // 键 (Long): 主分区id
        // 值 (MainChannelVo): 包含视频信息的对象
        Map<Long, BiliMainChannelVo> mainChannelVoMap = new HashMap<>();
        //获取所有主分区
        List<BiliMainChannel> biliMainChannels = biliMainChannelMapper.queryAllMainChannel();
        //打包需要缓存的数据至mainChannelVoMap
        //封装BiliVideoData数据
        //使用 foreach 循环遍历并操作每个对象
        biliMainChannels.forEach(biliMainChannel -> {
            BiliMainChannelVo biliMainChannelVo=new BiliMainChannelVo();
            //将BiliMainChannel对象中的数据复制到BiliMainChannelVo对象中
            BeanUtil.copyProperties(biliMainChannel, biliMainChannelVo);
            biliMainChannelVo.setMainChannelTag(Arrays.asList(biliMainChannel.getMainChannelTag().split(",")));
            //将BiliMainChannelVo对象放入mainChannelVoMap中
            mainChannelVoMap.put(biliMainChannel.getMainChannelId(), biliMainChannelVo);
        });

        // 将 map 的value值转换为 List, 拿到主分区数据list
        List<BiliMainChannelVo> mainChannelVoList = new ArrayList<>(mainChannelVoMap.values());

        //将主分区数据转换为json字符串
        return JSONUtil.toJsonStr(mainChannelVoList);
    }

}
